﻿namespace PlugNT.Common
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Text.RegularExpressions;

    public class JsonSimpleConvert
    {
        private static readonly string _COMMA = "@comma";
        private static readonly string _SEMICOLON = "@semicolon";

        private static string Deserialize(JsonObject _json, string text)
        {
            text = StrEncode(text);
            int count = 0;
            string key = string.Empty;
            string pattern = @"(\{[^\[\]\{\}]+\})|(\[[^\[\]\{\}]+\])";
            while (Regex.IsMatch(text, pattern))
            {
                MatchCollection matches = Regex.Matches(text, pattern);
                foreach (Match match in matches)
                {
                    key = "___key" + count + "___";
                    if (match.Value.Substring(0, 1) == "{")
                    {
                        _json.Add(key, DeserializeSingletonObject(_json, match.Value));
                    }
                    else
                    {
                        _json.Add(key, DeserializeSingletonArray(_json, match.Value));
                    }
                    text = text.Replace(match.Value, key);
                    count++;
                }
            }
            return text;
        }

        public static JsonArray DeserializeArray(string text)
        {
            JsonObject _json = new JsonObject();
            return (_json[Deserialize(_json, text)] as JsonArray);
        }

        public static JsonObject DeserializeObject(string text)
        {
            JsonObject _json = new JsonObject();
            return (_json[Deserialize(_json, text)] as JsonObject);
        }

        private static JsonArray DeserializeSingletonArray(JsonObject _json, string text)
        {
            JsonArray jsonArray = new JsonArray();
            MatchCollection matches = Regex.Matches(text, "(\\\"(?<value>[^,\\\"]+)\")|(?<value>[^,\\[\\]]+)");
            foreach (Match match in matches)
            {
                string value = match.Groups["value"].Value;
                jsonArray.Add(_json.ContainsKey(value) ? _json[value] : StrDecode(value));
            }
            return jsonArray;
        }

        private static JsonObject DeserializeSingletonObject(JsonObject _json, string text)
        {
            JsonObject jsonObject = new JsonObject();
            MatchCollection matches = Regex.Matches(text, "(\\\"(?<key>[^\\\"]+)\\\":\\\"(?<value>[^,\\\"]+)\\\")|(\\\"(?<key>[^\\\"]+)\\\":(?<value>[^,\\\"\\}]+))");
            foreach (Match match in matches)
            {
                string value = match.Groups["value"].Value;
                jsonObject.Add(match.Groups["key"].Value, _json.ContainsKey(value) ? _json[value] : StrDecode(value));
            }
            return jsonObject;
        }

        public static string SerializeArray(JsonArray jsonArray)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("[");
            for (int i = 0; i < jsonArray.Count; i++)
            {
                if (jsonArray[i] is JsonObject)
                {
                    sb.Append(string.Format("{0},", SerializeObject((JsonObject) jsonArray[i])));
                }
                else if (jsonArray[i] is JsonArray)
                {
                    sb.Append(string.Format("{0},", SerializeArray((JsonArray) jsonArray[i])));
                }
                else if (jsonArray[i] is string)
                {
                    sb.Append(string.Format("\"{0}\",", jsonArray[i]));
                }
                else
                {
                    sb.Append(string.Format("\"{0}\",", ""));
                }
            }
            if (sb.Length > 1)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            sb.Append("]");
            return sb.ToString();
        }

        public static string SerializeObject(JsonObject jsonObject)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("{");
            foreach (KeyValuePair<string, object> kvp in jsonObject)
            {
                if (kvp.Value is JsonObject)
                {
                    sb.Append(string.Format("\"{0}\":{1},", kvp.Key, SerializeObject((JsonObject) kvp.Value)));
                }
                else if (kvp.Value is JsonArray)
                {
                    sb.Append(string.Format("\"{0}\":{1},", kvp.Key, SerializeArray((JsonArray) kvp.Value)));
                }
                else if (kvp.Value is string)
                {
                    sb.Append(string.Format("\"{0}\":\"{1}\",", kvp.Key, kvp.Value));
                }
                else
                {
                    sb.Append(string.Format("\"{0}\":\"{1}\",", kvp.Key, ""));
                }
            }
            if (sb.Length > 1)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            sb.Append("}");
            return sb.ToString();
        }

        private static string StrDecode(string text)
        {
            return text.Replace(_SEMICOLON, ":").Replace(_COMMA, ",");
        }

        private static string StrEncode(string text)
        {
            MatchCollection matches = Regex.Matches(text, "\\\"[^\\\"]+\\\"");
            foreach (Match match in matches)
            {
                text = text.Replace(match.Value, match.Value.Replace(":", _SEMICOLON).Replace(",", _COMMA));
            }
            return text;
        }
    }
}

